/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package unilearn.bo;

import com.itextpdf.text.Document;
import com.itextpdf.text.PageSize;
import com.itextpdf.text.Paragraph;
import com.itextpdf.text.pdf.PdfWriter;
import java.io.BufferedInputStream;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import unilearn.dao.AssignmentDAO;
import unilearn.dao.StudentGroupDAO;
import unilearn.dao.SubjectDAO;
import unilearn.dao.SubjectMarkerDAO;
import unilearn.dao.SubjectStudentDAO;
import unilearn.dao.SubmissionDAO;
import unilearn.vo.Assignment;
import unilearn.vo.Person;
import unilearn.vo.Role;
import unilearn.vo.StudentGroup;
import unilearn.vo.SubjectStudent;
import unilearn.vo.Submission;

/**
 *
 * @author Ming
 */
public class SubmissionManagement {

    private static final DateFormat DF = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
    private String assignDirPath;
    private AccessValidator validator;
    private StudentGroupDAO studentGroupDAO;
    private SubjectDAO subjectDAO;
    private SubjectStudentDAO subjectStudentDAO;
    private SubjectMarkerDAO subjectMarkerDAO;
    private AssignmentDAO assignmentDAO;
    private SubmissionDAO submissionDAO;

    public SubmissionManagement() {
    }

    public SubmissionManagement(String assignDirPath, AccessValidator validator, StudentGroupDAO studentGroupDAO, SubjectDAO subjectDAO, SubjectStudentDAO subjectStudentDAO, SubjectMarkerDAO subjectMarkerDAO, AssignmentDAO assignmentDAO, SubmissionDAO submissionDAO) {
        this.assignDirPath = assignDirPath;
        this.validator = validator;
        this.studentGroupDAO = studentGroupDAO;
        this.subjectDAO = subjectDAO;
        this.subjectStudentDAO = subjectStudentDAO;
        this.subjectMarkerDAO = subjectMarkerDAO;
        this.assignmentDAO = assignmentDAO;
        this.submissionDAO = submissionDAO;
    }

    public void setAssignDirPath(String assignDirPath) {
        this.assignDirPath = assignDirPath;
    }

    public void setAssignmentDAO(AssignmentDAO assignmentDAO) {
        this.assignmentDAO = assignmentDAO;
    }

    public void setStudentGroupDAO(StudentGroupDAO studentGroupDAO) {
        this.studentGroupDAO = studentGroupDAO;
    }

    public void setSubjectDAO(SubjectDAO subjectDAO) {
        this.subjectDAO = subjectDAO;
    }

    public void setSubjectMarkerDAO(SubjectMarkerDAO subjectMarkerDAO) {
        this.subjectMarkerDAO = subjectMarkerDAO;
    }

    public void setSubjectStudentDAO(SubjectStudentDAO subjectStudentDAO) {
        this.subjectStudentDAO = subjectStudentDAO;
    }

    public void setSubmissionDAO(SubmissionDAO submissionDAO) {
        this.submissionDAO = submissionDAO;
    }

    public void setValidator(AccessValidator validator) {
        this.validator = validator;
    }

    public List<Submission> getAllSubmissions() throws Exception {
        return submissionDAO.getAll();
    }

    public List<Submission> getSubmissions(Assignment assignment) throws Exception {
        List<Submission> ss = this.getAllSubmissions();
        if ((ss == null) || (ss.isEmpty())) {
            return null;
        }

        List<Submission> subms = new ArrayList();
        for (Submission s : ss) {
            if (s.getAssignmentId() == assignment.getId()) {
                subms.add(s);
            }
        }

        return subms;
    }

//    public List<Submission> getSubmissions(Person person) throws Exception {
//        return this.getSubmissions(person, validator.getRole(person));
//    }
//
//    public List<Submission> getSubmissions(Person person, Role role) throws Exception {
////***
////***
//        return null;
//    }
//
//    private List<Submission> getStudentSubmissions(Person person) throws Exception {
//        SubjectStudent searchSS = new SubjectStudent();
//        searchSS.setPersonId(person.getId());
//        List<SubjectStudent> sss = subjectStudentDAO.find(searchSS);
//        if ((sss == null) || (sss.isEmpty())) {
//            return null;
//        }
//
//        for (SubjectStudent ss : sss) {
//            Assignment searchA = new Assignment();
//            searchA.setSubjectCode(ss.getSubjectCode());
//            List<Assignment> as = assignmentDAO.find(searchA);
//            if ((as == null) || (as.isEmpty())) {
//                return null;
//            }
//
//            for (Assignment a : as) {
//                int id = person.getId();
//                if (a.getType().equals("G")) {
//                    StudentGroup searchSG = new StudentGroup();
//                    studentGroupDAO.find(searchSG);
//                    //***
//                    //***
//                }
//            }
//
//        }
//
//        return null;
//    }

    public Submission getSubmission(int id) throws Exception {
        return submissionDAO.get(id);
    }

    public Submission createSubmission(Submission submission, String fileName, byte[] fileBytes) throws Exception {
        Assignment assign = assignmentDAO.get(submission.getAssignmentId());
        if (assign == null) {
            throw new Exception("Could not find this assignment(id: " + submission.getAssignmentId() + ").");
        }

        String dirPath = assignDirPath + "/" + assign.getSubjectCode() + "/" + assign.getId() + "/" + submission.getAutorId() + "/";

        submission.setFileUrl(dirPath + fileName);
        submission.setSubmissionDate(new Date());
        submission.setSubmissionStatus(0);

        //store assignment file
//        System.out.println("[createSubmission]store assignment file");//***
        storeFile(dirPath, fileName, fileBytes);

        //store recept file
//        System.out.println("[createSubmission]store recept file");//***
        generateRecept(assign, submission, dirPath);

        return submissionDAO.insert(submission);
    }

    public Submission updateSubmission(Submission submission, String fileName, byte[] fileBytes) throws Exception {
        Assignment assign = assignmentDAO.get(submission.getAssignmentId());
        if (assign == null) {
            throw new Exception("Could not find this assignment(id: " + submission.getAssignmentId() + ").");
        }

        String dirPath = assignDirPath + "/" + assign.getSubjectCode() + "/" + assign.getId() + "/" + submission.getAutorId() + "/";

        submission.setFileUrl(dirPath + fileName);
        submission.setSubmissionDate(new Date());
        storeFile(dirPath, fileName, fileBytes);

        return submissionDAO.update(submission);
    }

    public void removeSubmission(Submission submission) throws Exception {
        submissionDAO.delete(submission);
    }

    public byte[] getAssignmentFile(Submission submission) throws Exception {
        File file = new File(submission.getFileUrl());
        if (!file.exists()) {
            throw new Exception("Could not find assignment file(submission id: " + submission.getId() + ").");
        }

        return getFileBytes(file);
    }

    public byte[] getReceptFile(Submission submission) throws Exception {
        String filePath = submission.getFileUrl();
//        System.out.println("[getReceptFile][0]filePath: " + filePath);//***
        filePath = filePath.substring(0, filePath.lastIndexOf("/") + 1);
//        System.out.println("[getReceptFile][1]filePath: " + filePath);//***
        File file = new File(filePath + "recept.pdf");

        if (!file.exists()) {
            throw new Exception("Could not find recept file(submission id: " + submission.getId() + ").");
        }

        return getFileBytes(file);
    }

    private byte[] generateRecept(Assignment assignment, Submission submission, String dirPath) throws Exception {
        ByteArrayOutputStream baos = null;
        try {
            baos = new ByteArrayOutputStream();

            Document document = new Document(PageSize.A4, 50, 50, 50, 50);
            PdfWriter writer = PdfWriter.getInstance(document, baos);
            document.open();

            document.add(new Paragraph("Submit Date: " + DF.format(submission.getSubmissionDate())));
            document.add(new Paragraph("Subject Code: " + submission.getSubjectCode()));
            document.add(new Paragraph("Assignment Name: " + assignment.getName()));
            document.add(new Paragraph("Autor ID(Student ID / Group ID): " + submission.getAutorId()));

            String fileName = submission.getFileUrl();
//            System.out.println("[generateRecept][0]filePath: " + fileName);//***
            fileName = fileName.substring(fileName.lastIndexOf("/") + 1);
//            System.out.println("[generateRecept][1]filePath: " + fileName);//***
            document.add(new Paragraph("Assignment File Name: " + fileName));
            document.close();

            //get byte array and store recept file
            byte[] recBytes = baos.toByteArray();
            storeFile(dirPath, "recept.pdf", recBytes);

            return recBytes;
        } finally {
            try {
                if (baos != null) {
                    baos.flush();
                    baos.close();
                }
            } catch (IOException e) {
            }
        }
    }

    private void storeFile(String dirPath, String fileName, byte[] fileBytes) throws Exception {
        FileOutputStream fos = null;
        ByteArrayInputStream bais = null;

        try {
            File dir = new File(dirPath);
            if (!dir.exists()) {
                dir.mkdirs();
            }
            File file = new File(dirPath + fileName);
            if (!file.exists()) {
                file.createNewFile();
            }
            fos = new FileOutputStream(file);
            bais = new ByteArrayInputStream(fileBytes);

            byte[] buf = new byte[bais.available()];
            int len = 0;
            while ((len = bais.read(buf)) > 0) {
                fos.write(buf, 0, len);
            }
        } finally {
            try {
                if (fos != null) {
                    fos.flush();
                    fos.close();
                }
                if (bais != null) {
                    bais.close();
                }
            } catch (Exception e) {
            }
        }
    }

    private byte[] getFileBytes(File file) throws IOException {
        FileInputStream fis = new FileInputStream(file);

        BufferedInputStream bis = new BufferedInputStream(fis);
        byte[] fileBytes = new byte[bis.available()];
        int offset = 0;
        int numRead = 0;
        while (offset < fileBytes.length
                && (numRead = bis.read(fileBytes, offset, fileBytes.length - offset)) >= 0) {
            offset += numRead;
        }

        return fileBytes;
    }
}
